package cn.com.cifi.mars.web.action.operateplan;


import java.io.IOException;
import java.io.OutputStream;
import java.net.URLEncoder;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import cn.com.cifi.mars.bean.bo.ProjectProductBO;
import cn.com.cifi.mars.bean.bo.StartAndEndTimeBO;
import cn.com.cifi.mars.bean.bo.SysLogBO;
import cn.com.cifi.mars.bean.dto.SignPlanVersionDetailDto;
import cn.com.cifi.mars.bean.vo.signPlan.FullPathVo;
import cn.com.cifi.mars.bean.vo.signPlan.ProductSignPlanVo;
import cn.com.cifi.mars.bean.vo.signPlan.SigPlanPreviewVo;
import cn.com.cifi.mars.bean.vo.signPlan.SignPlanVersionVo;
import cn.com.cifi.mars.bean.vo.signPlan.SignProductVo;
import cn.com.cifi.mars.bean.vo.signPlan.req.ProductSignPlanParam;
import cn.com.cifi.mars.bean.vo.signPlan.req.SignPlanDetailParam;
import cn.com.cifi.mars.bean.vo.signPlan.req.SignPlanOaParam;
import cn.com.cifi.mars.bean.vo.signPlan.signOverall.OverallSignPlanVo;
import cn.com.cifi.mars.common.base.BaseAction;
import cn.com.cifi.mars.common.bean.R;
import cn.com.cifi.mars.common.exception.MsgException;
import cn.com.cifi.mars.common.redis.RedisTemplateUtil;
import cn.com.cifi.mars.constant.CodeEnum;
import cn.com.cifi.mars.constant.Constants;
import cn.com.cifi.mars.constant.IsDeleteEnum;
import cn.com.cifi.mars.constant.LogEventEnum;
import cn.com.cifi.mars.constant.LogSrcEnum;
import cn.com.cifi.mars.constant.StageStatusEnum;
import cn.com.cifi.mars.constant.VersionStatusEnum;
import cn.com.cifi.mars.constant.VersionTypeEunm;
import cn.com.cifi.mars.constant.WhetherEnum;
import cn.com.cifi.mars.entity.MdmProject;
import cn.com.cifi.mars.entity.MdmStage;
import cn.com.cifi.mars.entity.SignPlanVersion;
import cn.com.cifi.mars.entity.common.IdmUser;
import cn.com.cifi.mars.mapper.mars.ProjectMapper;
import cn.com.cifi.mars.mapper.mars.SignPlanVersionMapper;
import cn.com.cifi.mars.schedled.SignPlanTasks;
import cn.com.cifi.mars.service.BudgetVersionIdentifyService;
import cn.com.cifi.mars.service.SignPlanVersionDetailService;
import cn.com.cifi.mars.service.SignPlanVersionService;
import cn.com.cifi.mars.service.StageService;
import cn.com.cifi.mars.service.SysLogService;
import cn.com.cifi.mars.util.LocalDateTimeUtils;
import cn.com.cifi.mars.util.OverallSignPlanTemplate;
import cn.com.cifi.mars.util.WebUtils;
import lombok.extern.slf4j.Slf4j;

/**
 * <p>
 * 签约计划版本表 前端控制器
 * </p>
 *
 * @author yyd
 * @since 2019-11-08
 */
@Slf4j
@RestController
public class SignPlanController extends BaseAction implements ISignPlanController {

	@Autowired
	private SignPlanVersionService signPlanVersionService;

	@Autowired
	private SignPlanVersionDetailService signPlanVersionDetailService;
	@Autowired
	private SignPlanTasks signPlanTasks;
	@Autowired
	private ProjectMapper projectMapper;
	@Autowired
	private SysLogService sysLogService;
	@Autowired
	private RedisTemplateUtil redisTemplateUtil;
	@Autowired
	private RedisTemplate redisTemplate;
	@Autowired
	private SignPlanVersionMapper signPlanVersionMapper;
	@Autowired
	private StageService stageService;
	@Autowired
	private BudgetVersionIdentifyService budgetVersionIdentifyService;
	
	/**
	 * 创建签约计划版本
	 */
	@Override
	public R createSignPlanVersion(String apiVersion, String projectFid, String versionType,String versionIdentify) {
		String alias = getOperator().getAlias();

		String key = Constants.SIGN_CREATE_VERSION_LOCK + projectFid + "_" + versionType;
		//2s内禁止重复创建
		Boolean aBoolean = redisTemplate.opsForValue().setIfAbsent(key, 1, 2, TimeUnit.SECONDS);
		if (!aBoolean) {
			throw new MsgException(CodeEnum.SYS_EXISTENT);
		}

		return ok(signPlanVersionService.createSignPlan(projectFid,versionType,versionIdentify,alias));
	}

	/**
	 * 异常新建签约计划版本
	 */
	@Override
	public R exceptionCreateSignPlanVersion(String apiVersion, String projectFid, String versionType,String versionIdentify) {
		String alias = getOperator().getAlias();
		return ok(signPlanVersionService.exceptionCreate(projectFid,versionType,versionIdentify,alias));
	}


	/**
	 * 删除签约计划版本
	 */
	@Override
	public R deleteSignPlanVersion(String apiVersion, String versionId) {
		String alias = getOperator().getAlias();
		return ok(signPlanVersionService.deleteSignPlanVersion(versionId,alias));
	}

	/**
	 * 查询签约计划版本展示
	 */
	@Override
	public R<SignPlanVersionVo> getSignPlanVersion(String apiVersion, String versionId, String year) {
		SignPlanVersionVo vo = signPlanVersionService.getSignPlanVersion(versionId, year);
		return ok(vo);
	}

	/**
	 * 查询产品构成的签约计划
	 */
	@Override
	public R<ProductSignPlanVo> getProductSignPlan(String apiVersion,ProductSignPlanParam productSignPlanParam) {
        ProductSignPlanVo vo = signPlanVersionDetailService.getProductSignPlan(productSignPlanParam);
		return ok(vo);
	}

	/**
	 * 查询签约版本全路径名称与来源版本全路径名称
	 */
	@Override
	public R<FullPathVo> getSignFullPath(String apiVersion, String versionId) {
		return ok(signPlanVersionService.getSignFullPath(versionId));
	}

	/**
	 * 查询签约版本全路径名称与来源版本全路径名称列表
	 */
	@Override
	public R<List<FullPathVo>> getSignFullPathList(String apiVersion, String projectFid, String versionType) {
		return ok(signPlanVersionService.getSignFullPathList(projectFid,versionType));
	}

	/**
	 * 保存组合业态签约计划
	 */
	@Override
	public R saveProductSignPlan(String apiVersion, SignPlanDetailParam signPlanDetailParam) {
		String content = "signPlanDetailParam:"+signPlanDetailParam.toString();
		addLog(LogEventEnum.PRESERVATION,LogSrcEnum.PC,"保存组合业态签约计划",content);
		String alias = getOperator().getAlias();
		return ok(signPlanVersionService.saveProductSignPlan(signPlanDetailParam,alias));
	}

	/**
	 * 查询该分期最新版本
	 */
	@Override
	public R getNewVersionType(String apiVersion, String projectFid) {
		return ok(signPlanVersionService.getNewVersionType(projectFid));

	}
	
	/**
	 * 查询签约计划审批预览PC段
	 */
	@Override
	public R<SigPlanPreviewVo> getApprovalPreview(String apiVersion, String projectId,String billId) {
		return ok(signPlanVersionService.getApprovalPreview(projectId,billId));
	}

	/**
	 * 查询全盘签约
	 */
	@Override
	public R<SignPlanVersionVo> getOverallSignPlanVersion(String apiVersion, String projectId, String year, String code) {
		SignPlanVersionVo vo = new SignPlanVersionVo();

		//1、查询全盘签约计划版本列表
		List<String> versionIds = signPlanVersionService.getOverallSignVersionList(projectId);
		if(CollectionUtils.isEmpty(versionIds)){
			return ok(null);
		}
		//2、获取版本列表中全盘签约数据
		List<SignPlanVersionDetailDto> detailList = signPlanVersionService.getOverallSignPlanListDate(projectId,year,code,versionIds);
		//3、版本列表全周期年份列表
		List<String> timeList = signPlanVersionService.getDateList(versionIds);
		vo.setDetailList(detailList);
		vo.setTimeList(timeList);
        return ok(vo);
	}
	
	/**
	 * 查询签约计划审批预览App段
	 */
	@Override
	public R<SigPlanPreviewVo> getApprovalPreviewApp(String apiVersion, String projectId,String billId) {
		return ok(signPlanVersionService.getApprovalPreview(projectId,billId));
	}

	/**
	 * 签约审批-提交到OA审批
	 */
	@Override
	public R<String> submitToOA(String apiVersion,SignPlanOaParam signPlanOaParam) {
		String content = "signPlanOaParam:"+signPlanOaParam.toString();
		addLog(LogEventEnum.SUBMISSION,LogSrcEnum.PC,"提交到OA审批",content);
		 IdmUser user = getOperator();
		return ok(signPlanVersionService.submitToOA(signPlanOaParam,user));
	}

	/**
	 * 签约检查是否可以提交审批
	 */
	@Override
	public R<Map<String, Boolean>> approvedCheck(String apiVersion, String projectId) {
		Map<String, Boolean> map = new HashMap<>();
		if (StringUtils.isNotBlank(projectId)) {
			int num = signPlanVersionService.checkApprovedVersionIsNull(projectId);
			if (num == 0) {
				throw new MsgException(CodeEnum.SIGN_PLAN_VERSION_IS_NULL);
			} else {
				// 是否存在编制中，待提交审批，已驳回的版本
				List<SignPlanVersion> priceVersionList = signPlanVersionService.selectApprovedProject(projectId);
				if (CollectionUtils.isEmpty(priceVersionList)) {
					throw new MsgException(CodeEnum.APPROVED_NON_EXISTENT);
				}
				// 存在待编制或审批中的版本，不能提交审批
				int count = signPlanVersionService.checkApprovedVersion(projectId);
				if (count > 0) {
					throw new MsgException(CodeEnum.NOT_APPROVED);
				}
				//项目下编制中的版本id
				List<String> str = Arrays.asList(VersionStatusEnum.ORGANIZATION.getKey(),VersionStatusEnum.FAILUREAPPROVED.getKey(),VersionStatusEnum.EXAMINEDAPPROVED.getKey());
				List<String> versionIds = signPlanVersionMapper.selectOrganizationIds(projectId, IsDeleteEnum.NO.getKey(), str);
				if (CollectionUtils.isEmpty(versionIds)) {
					throw new MsgException(CodeEnum.SIGN_PLAN_ORGANIZATION_ERROR);
				}
				//判断签约版本中是否存在未编制完成的数据
				boolean isEstablishment = signPlanVersionService.isEstablishment(versionIds);
				if(isEstablishment){
					// 存在还没有编制完成的版本
					throw new MsgException(CodeEnum.ESTABLISHMENTNUM_ERROR);
				}
				//版本数据列表
				List<SignPlanVersion> signPlanVersions = signPlanVersionMapper.selectByVersionIds(versionIds, WhetherEnum.NO.getKey());
				for (SignPlanVersion signPlanVersion : signPlanVersions) {
					MdmStage mdmStage = stageService.selectById(signPlanVersion.getProjectfId());
					if (StageStatusEnum.INACTIVE.getKey().equals(mdmStage.getStatus())) {
						throw new MsgException(CodeEnum.APPROVED_INACTIVE_STAGE_ERROR);
					}
					if (!signPlanVersionService.getStageIsSaly(signPlanVersion.getProjectfId())) {
						throw new MsgException(CodeEnum.APPROVED_NOT_BUILD_SALY_TYPE_ERROR);
					}
				}
				map.put("result", true);
				return ok(map);
			}
		}
		return ok("请输入正确的参数");
	}


	/**
	 * 全盘签约计划报表导出
	 * @param apiVersion
	 * @param response
	 * @param projectId 项目id
	 */
	@Override
	public void overallSignPlanExport(String apiVersion,HttpServletResponse response, String projectId) {
		List<OverallSignPlanVo> voList = new ArrayList<>();

		//1、查询全盘签约计划版本列表
        List<String> versionIds = signPlanVersionService.getOverallSignVersionList(projectId);
        if(CollectionUtils.isEmpty(versionIds)){
        	return;
		}
		//查询分期下最早供货时间与最晚签约时间
		StartAndEndTimeBO startAndEndTimeBO = signPlanVersionService.getStartAndEndTime(versionIds);
        if(CollectionUtils.isNotEmpty(versionIds)){
			//获取项目全盘签约计划报表数据
			voList = signPlanVersionService.getOverallSignPlanReport(projectId,versionIds,startAndEndTimeBO);
			//数据精度修改(套数、套均面积、面积保留两位小数,均价、金额取整)
			signPlanVersionService.updateOverallSignPlanVoAccuracy(voList);
		}
		MdmProject mdmProject = projectMapper.selectByProjectId(projectId, IsDeleteEnum.NO.getKey());
		String projectName = mdmProject.getProjectName();
        boolean contains = projectName.contains("/");
        if(contains){
            projectName = projectName.replace("/", "_");
        }
        //报表名称
		String exportName = projectName+"全盘签约计划-".concat(LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHH")));
		//报表导出
		OverallSignPlanTemplate overallSignPlanTemplate = new OverallSignPlanTemplate(startAndEndTimeBO,exportName);
		overallSignPlanTemplate.appendRows(voList, WhetherEnum.NO.getKey());
		try (OutputStream outputStream = response.getOutputStream()){
			response.setContentType("application/vnd.ms-excel");
			response.setHeader("Content-Disposition", "attachment;filename="+ URLEncoder.encode(exportName.concat(".xlsx"), "utf-8"));
			overallSignPlanTemplate.write(outputStream);
			outputStream.flush();
		} catch (IOException e) {
			log.error("###### errorMsg: ", e);
		}
	}

	/**
	 * 签约计划版本导出
	 * @param apiVersion
	 * @param response
	 * @param versionId 版本id
	 */
	@Override
	public void signPlanVersionExport(String apiVersion, HttpServletResponse response, String versionId) {

		SignPlanVersion signPlanVersion = signPlanVersionService.selectById(versionId);
		if(null == signPlanVersion || signPlanVersion.getIsDelete() == WhetherEnum.YES.getKey()){
			throw new MsgException(CodeEnum.NOT_SIGN_PLAN_VERSION);
		}
		String projectId = signPlanVersion.getProjectId();

		List<String> versionIds = new ArrayList<>();
		versionIds.add(versionId);
		//查询分期下最早供货时间与最晚签约时间
		StartAndEndTimeBO startAndEndTimeBO = signPlanVersionService.getStartAndEndTime(versionIds);

		//获取项目全盘签约计划报表数据
		List<OverallSignPlanVo> voList = signPlanVersionService.getOverallSignPlanReport(projectId,versionIds,startAndEndTimeBO);
		//数据精度修改(套数、套均面积、面积保留两位小数,均价、金额取整)
		signPlanVersionService.updateOverallSignPlanVoAccuracy(voList);

		//报表名称
		String exportName = getExportName(signPlanVersion);
		//报表导出
		OverallSignPlanTemplate overallSignPlanTemplate = new OverallSignPlanTemplate(startAndEndTimeBO,exportName);
		overallSignPlanTemplate.appendRows(voList,WhetherEnum.YES.getKey());
		try (OutputStream outputStream = response.getOutputStream()){
			response.setContentType("application/vnd.ms-excel");
			response.setHeader("Content-Disposition", "attachment;filename="+ URLEncoder.encode(exportName.concat(".xlsx"), "utf-8"));
			overallSignPlanTemplate.write(outputStream);
			outputStream.flush();
		} catch (IOException e) {
			log.error("###### errorMsg: ", e);
		}
	}

	//拼接报表名称
	private String getExportName(SignPlanVersion spv){
		String exportName;

		//最后更新时间
		LocalDateTime updateTime = spv.getUpdateTime();
		if(updateTime==null){
			updateTime=spv.getCreateTime();
		}

		//最后更新时间年-月-日
		String updateName = LocalDateTimeUtils.formatTime(updateTime, "yyyyMMdd");
		String timeName = LocalDateTimeUtils.formatTime(LocalDateTime.now(), "yyyyMMddHH");


		String projectId = spv.getProjectId();
		MdmProject mdmProject = projectMapper.selectByProjectId(projectId, IsDeleteEnum.NO.getKey());
		String projectName = mdmProject.getProjectName();
        boolean contains = projectName.contains("/");
        if(contains){
            projectName = projectName.replace("/", "_");
        }
		String stageName = spv.getStageName();
		String versionNum = spv.getVersionNum();
		String versionType = spv.getVersionType();
		String versionName = VersionTypeEunm.getValueByKey(versionType);
		String versionState = spv.getVersionState();

		if(versionType.equals(VersionTypeEunm.BUDGET.getKey())){
			exportName = projectName+stageName+"签约计划-" + spv.getVersionIdentify() + versionNum;
		}else if(versionType.equals(VersionTypeEunm.DYNAMIC.getKey())){
			//归属月份
			String yearMonth = spv.getAffiliationMonth().replace("-", "");
			exportName = projectName+stageName+"签约计划-" + yearMonth + "月" + versionName+versionNum;
		}else {
			exportName = projectName+stageName+"签约计划-" + versionName+versionNum;
		}
		if(versionState.equals(VersionStatusEnum.SUCCESSAPPROVED.getKey())){
			exportName=exportName + "-" + updateName;
			if (spv.getIsAssessmentVersion()!=null && spv.getIsAssessmentVersion().equals(IsDeleteEnum.YES.getKey())){
				exportName = exportName + "(考核版)";
			}
			exportName=exportName + "-"+timeName;
		}else {
			if (spv.getIsAssessmentVersion()!=null && spv.getIsAssessmentVersion().equals(IsDeleteEnum.YES.getKey())){
				exportName = exportName + "(考核版)";
			}
			exportName=exportName + "-"+timeName;
		}
		return exportName;
	}

	/**
	 * 查询产品构成列表
	 * @param apiVersion
	 * @param versionId 版本id
	 * @return
	 */
	@Override
	public R<List<SignProductVo>> getProductList(String apiVersion, String versionId) {

		return ok(signPlanVersionService.getProductList(versionId));
	}

	/**
	 * 查询全盘签约概览
	 * @param apiVersion
	 * @param versionId 版本id
	 * @param year 年份
	 * @param month 月份
	 * @return
	 */
	@Override
	public R<List<ProjectProductBO>> getProjectProductList(String apiVersion, String versionId, String year,String month) {
		return ok(signPlanVersionService.getProjectProductList(versionId,year,month));
	}

	/**
	 * 设置考核版
	 * @param apiVersion
	 * @param versionId 版本id
	 * @return
	 */
	@Override
	public R settingsAssessmentVersion(String apiVersion, String versionId) {
		return ok(signPlanVersionService.settingsAssessmentVersion(versionId));
	}

	/**
	 * 查询门户代办
	 * @param apiVersion
	 * @param id 分期id+版本类型code
	 * @return
	 */
	@Override
	public R getPortalTodo(String apiVersion, String id) {
		return ok(signPlanVersionService.getPortalTodo(id));
	}
	
	@Override
	public R copyBudgetVersion(String apiVersion, String versionId) {
		IdmUser user = getOperator();
		String versionIdentify = budgetVersionIdentifyService.getVersion();
		signPlanVersionDetailService.copyToBudgetVersion(versionId,versionIdentify,user);
		return ok();
	}
	

	@Override
	public R copySignPlanVersion(String apiVersion, String versionId) {
		IdmUser user = getOperator();
		String versionIdentify = budgetVersionIdentifyService.getVersion();
		signPlanVersionDetailService.copyBudgetVersion(versionId,versionIdentify,user);
		return ok();
	}

	/**
	 * 手动刷新实际签约数据
	 * @param apiVersion
	 * @param versionId 版本id
	 * @param yearMonth 刷新年月
	 * @return
	 */
	@Override
	public R refreshSignData(String apiVersion, String versionId,String yearMonth) {
		List<SignPlanVersion> spvdList = new ArrayList<>();
		switch (apiVersion){
			case "v1":
				SignPlanVersion signPlanVersion = signPlanVersionService.selectById(versionId);
				spvdList.add(signPlanVersion);
				break;
			case "v2":
				//查询各分期下当前年月的最新动态版签约计划
				spvdList = signPlanVersionMapper.selectLatestVersionByVersionTypeAndAffiliationMonth(VersionTypeEunm.DYNAMIC.getKey(),yearMonth, IsDeleteEnum.NO.getKey());
				break;
		}
		signPlanTasks.refreshSignData(spvdList,yearMonth);
		return ok("刷新成功");
	}

    /**
     * 发送代办
     * @param supplyId 供货版本id
     */
    @Override
    public R signNoticeDispose(String apiVersion,String supplyId) {
        signPlanVersionService.signNoticeDispose(supplyId);
        return ok();
    }

    /**
     * 消除代办
     * @param
     */
	@Override
	public R deleteTodoInfo(String apiVersion,String id,String operatorType) {
		IdmUser handUser = new IdmUser();
		handUser.setAlias(Constants.SYS);
		handUser.setUsercn("系统");
        String s = signPlanVersionService.deleteTodoInfo(id,operatorType,handUser);
        return ok(s);
	}

	@Override
	public R updateState(String apiVersion, List<String> versionIds, String versionState) {
		IdmUser user = getOperator();
		signPlanVersionService.updateState(versionIds,versionState,user);
		return ok();
	}

	/**
	 * 添加日志
	 * @param event 操作事件
	 * @param source 来源
	 * @param title 标题
	 * @param content 内容
	 */
	private void addLog(LogEventEnum event,LogSrcEnum source,String title,String content){
		HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
		IdmUser user = getOperator();
		SysLogBO bo = new SysLogBO();
		bo.setEvent(event);
		bo.setSource(source);
		bo.setIp(WebUtils.getIpAddr(request));
		bo.setUrl(WebUtils.getUrl(request));
		bo.setModule("签约计划");
		bo.setTitle(title);
		bo.setContent(content);
		if(null != user){
			sysLogService.add(bo, user.getAlias());
		}
	}

}
